package com.smartstate.EnvironmentMonitor.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smartstate.EnvironmentMonitor.PowerEquipmentJobClient;
import com.smartstate.EnvironmentMonitor.dto.AlarmDTO;
import com.smartstate.EnvironmentMonitor.dto.AlarmVO;
import com.smartstate.EnvironmentMonitor.dto.EquipmentDTO;
import com.smartstate.EnvironmentMonitor.dto.PageDTO;
import com.smartstate.EnvironmentMonitor.entity.Alarm;
import com.smartstate.EnvironmentMonitor.exception.ErrorEnums;
import com.smartstate.EnvironmentMonitor.exception.MyRException;
import com.smartstate.EnvironmentMonitor.mapper.AlarmMapper;
import com.smartstate.EnvironmentMonitor.mapper.ObjMoudelMapper;
import com.smartstate.EnvironmentMonitor.mqtt.client.MyMQTTClient;
import com.smartstate.EnvironmentMonitor.mqtt.common.GlobalMqttParam;
import com.smartstate.EnvironmentMonitor.service.AlarmService;
import com.smartstate.EnvironmentMonitor.util.SpringUtils;
import com.smartstate.EnvironmentMonitor.vo.AlarmPageVo;
import com.smartstate.EnvironmentMonitor.vo.AlarmVo;
import com.smartstate.EnvironmentMonitor.vo.EquipMentVo;
import com.smartstate.EnvironmentMonitor.vo.EquipmentConfigurationVo;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>报警信息</p>
 * <p>@Author 陈永杰</p>
 * <p>@Date: 2022/8/16</p>
 * <p>@Time: 10:38</p>
 * <p>@version 1.0 <p>
 */

@Transactional
@Service("alarmService")
@Slf4j
public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements AlarmService {


    @Resource
    private AlarmMapper alarmMapper;

    @Autowired
    PowerEquipmentJobClient powerEquipmentJobClient;

    @Resource
    private ObjMoudelMapper objMoudelMapper;

    private Map<String, Object> objectMap = null;

    private Map<String, Object> deviceIdMap = null;



    /**
     * MQTT连接配置
     */
    GlobalMqttParam globalMqttParam = SpringUtils.getBean(GlobalMqttParam.class);
    String broker = globalMqttParam.getBroker();
    String userName = globalMqttParam.getUserName();
    String passWord = globalMqttParam.getPassWord();
    String clientId1 = globalMqttParam.getSubClientId1() + System.currentTimeMillis();
    int keepalive = globalMqttParam.getKeepalive();
    int timeout = globalMqttParam.getTimeout();
    MyMQTTClient myMQTTClient = new MyMQTTClient(broker, userName, passWord, clientId1, keepalive, timeout);


    /**
     * 获取湿度 设备名称 和楼宇id 和报警信息 分页
     *
     * @param
     * @return
     */
    @Override
    public Page<Alarm> queryPageList(PageDTO<AlarmPageVo> pageDTO) {
        Page<Alarm> page = new Page(pageDTO.getPage(), pageDTO.getSize());
        return alarmMapper.queryPageByCondition(page, pageDTO.getDto());
    }


    /**
     * 处理完成
     * @param alarm
     * @return
     */
    @Override
    public Boolean figureOut(Alarm alarm) {
        if (alarm.getState()!= null && !"".equals(alarm.getState()) && alarm.getState().equals("1")){
            Date dates = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss");
            String format = dateFormat.format(dates);
            alarm.setStopTime(format);
        }
        return this.saveOrUpdate(alarm);
    }

    /**
     * 获取湿度 设备名称 和楼宇id 和报警信息
     *
     * @param item
     * @return
     */
    @Override
    public List<AlarmVo> selectAlarm(AlarmDTO item) {
        return alarmMapper.selectAlarm(item);
    }


    /**
     * 实时数据  查所有报警信息未处理的
     *
     * @return
     */
    @Override
    public List<AlarmVo> selectAlarmTime() {
        return alarmMapper.selectAlarmTime();
    }

    /**
     * 实时数据 控制面板
     *
     * @param deviceId
     * @return
     */
    @Override
    public EquipMentVo selectTags(String deviceId) {
        return alarmMapper.selectTags(deviceId);
    }

    @Override
    public EquipMentVo selectDeviceId(String deviceId) {
        return alarmMapper.selectTages(deviceId);
    }

    /**
     * 关闭 报警
     *
     * @param deviceId
     * @param tags
     * @param way
     * @return
     */
    @Override
    public int updateDeviceIdTags(String deviceId, String tags, String way) {
        HashMap<String, Object> hashMap = new HashMap<>();
        int i = 0;
        boolean s = true;
        List<EquipmentDTO.AddressData> addressDataList = JSONArray.parseArray(tags, EquipmentDTO.AddressData.class);
        for (EquipmentDTO.AddressData addressData : addressDataList) {
            if (addressData.getIsAlarm().equals("0")) {
                Date dates = new Date();
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss");
                alarmMapper.updateAlarmAttributes(deviceId, addressData.getAttributeAlias(), "报警设置关闭", dateFormat.format(dates));
            }
            if ((addressData.getUp() != null && !"".equals(addressData.getUp())) && (addressData.getDown() != null && !"".equals(addressData.getDown()))) {
                if (Float.parseFloat(addressData.getUp()) < Float.parseFloat(addressData.getDown())) {
                    s = false;
                    break;
                }
            }

        }
        if (s) {
            if (Objects.equals(way, "box")) {

                List<EquipmentConfigurationVo> list = new ArrayList<>();
                for (EquipmentDTO.AddressData addressData : addressDataList) {
                    EquipmentConfigurationVo es = new EquipmentConfigurationVo();
                    es.setDataId(addressData.getDataId());
                    es.setUpLimit(addressData.getUp());
                    es.setDownLimit(addressData.getDown());
                    es.setIsAlarm( "1".equals(addressData.getIsAlarm()) ? "true" : "false");
                    es.setDeviation(addressData.getDeviation());
                    list.add(es);
                }
                i = alarmMapper.updateDeviceIdTags(deviceId, tags);
                if (i > 0) {
                    try {
                        myMQTTClient.connect();
                        myMQTTClient.publish(JSON.toJSONString(list), "SH/NJ/HK/ALL/CONFIGS");
                        System.out.println("MQTT消息发送成功");
                    } catch (MqttException e) {
                        throw new RuntimeException(e);
                    }
                }
                return i;
            } else if (Objects.equals(way, "plc")) {

                hashMap.put("id", deviceId);

                List<Map<String, String>> list = new ArrayList<>();
                for (EquipmentDTO.AddressData addressData : addressDataList) {

                    Map<String, String> map = new HashMap<>();

                    Map<String, String> mapOne = new HashMap<>();

                    Map<String, String> mapTwo = new HashMap<>();

                    Map<String, String> mapThree = new HashMap<>();
                    //上限
                    if (addressData.getUp() != null && !"".equals(addressData.getUp())) {
                        map.put("attributeName", addressData.getDataId() + "up");
                        map.put("value", addressData.getUp());
                        list.add(map);
                    }

                    //下限
                    if (addressData.getDown() != null && !"".equals(addressData.getDown())) {
                        mapOne.put("attributeName", addressData.getDataId() + "down");
                        mapOne.put("value", addressData.getDown());

                        list.add(mapOne);
                    }
                    //是否报警
                    if (addressData.getIsAlarm() != null && !"".equals(addressData.getIsAlarm())) {
                        mapTwo.put("attributeName", addressData.getDataId() + "IsAlarm");
                        mapTwo.put("value", "1".equals(addressData.getIsAlarm()) ? "true" : "false");

                        list.add(mapTwo);
                    }
                    //补偿值
                    if (addressData.getDeviation() != null && !"".equals(addressData.getDeviation())) {
                        mapThree.put("attributeName", addressData.getDataId() + "Deviation");
                        mapThree.put("value", addressData.getDeviation());
                        list.add(mapThree);
                    }
                }
                hashMap.put("WriteParameters", list);
                i = alarmMapper.updateDeviceIdTags(deviceId, tags);
                if (i > 0) {
                    try {
                        myMQTTClient.connect();
                        myMQTTClient.publish(JSON.toJSONString(hashMap), "SH/NJ/HK/PLC/CONFIGS");
                        System.out.println("MQTT消息发送成功");
                    } catch (MqttException e) {
                        throw new RuntimeException(e);
                    }
                }
                return i;
            }

        } else {
            throw new MyRException(ErrorEnums.UPPER_LIMIT);
        }
        //TODO
        return 1;
    }

    private Alarm alarm;

    public Alarm getAlarm() {
        return alarm;
    }

    public void setAlarm(Alarm alarm) {
        this.alarm = alarm;
    }


    Set<String> set = new HashSet<>();

    Set<String> setTwo = new HashSet<>();

    /**
     * 添加报警信息
     *
     * @param
     * @return
     */
    @Override
    @Scheduled(cron = "0/1 * * * * ?")
    public void addAlarm() {
        ArrayList<AlarmVO> arrayList = powerEquipmentJobClient.equipmentTags();
        if (arrayList.size() > 0) {
            //查询空间结构中的所有objId
            objectMap = objMoudelMapper.queryAllObjId("1");
            //查询所有设备对应空间建模的所有objId
            deviceIdMap = objMoudelMapper.queryAllDeviceIdFitAllObjId("1");

            for (AlarmVO alarmDateVO : arrayList) {
                if (alarmDateVO.getType().equals("正常") || alarmDateVO.getType().equals("异常")) {
                    //拿到上下限值 先判断是不是报警信息 如果是报警信息 就去查报警表 查有没有相同的报警信息
                    //down 是下限  up是上限  必须不低于下限 不高于上限
                    float deviation = 0.00F;
                    float down = 0.00F;
                    float up = 0.00F;


                    //无偏差值 但是 上限为空 下限不为空
                    if ((alarmDateVO.getDown() != null && !"".equals(alarmDateVO.getDown())) && ("".equals(alarmDateVO.getUp()) || alarmDateVO.getUp() == null)) {
                        down = Float.parseFloat(alarmDateVO.getDown());
                        //无偏差值 但是 下限为空 上限不为空
                    } else if ((alarmDateVO.getDown() == null || "".equals(alarmDateVO.getDown())) && (!"".equals(alarmDateVO.getUp()) && alarmDateVO.getUp() != null)) {
                        up = Float.parseFloat(alarmDateVO.getUp());
                        //无偏差 但是 上下限都不为空
                    } else if ((!"".equals(alarmDateVO.getUp()) && alarmDateVO.getUp() != null) && (alarmDateVO.getDown() != null && !"".equals(alarmDateVO.getDown()))) {
                        down = Float.parseFloat(alarmDateVO.getDown());
                        up = Float.parseFloat(alarmDateVO.getUp());
                    }

                    //上下限全有
                    if (up < alarmDateVO.getNow() || down > alarmDateVO.getNow()) {
                        //收集到所有报警值信息
                        set.add(alarmDateVO.getDeviceId() + "+" + alarmDateVO.getAttributeAlias());
                        //如果是报警信息 去查报警表里有没有相同的报警信息
                        Alarm alarmId = alarmMapper.selectEquipmentId(alarmDateVO.getDeviceId(), alarmDateVO.getAttributeAlias());
                        //拿到报警表里的设备id  如果数据库有相同的deviceId  2是没有处理完的报警信息会返回信息  1是处理完成的信息返回空
                        if (alarmId == null) {
                            String id = IdUtil.simpleUUID();
                            Date date = new Date();
                            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss");
                            Alarm alarmIndex = new Alarm();
                            //拿到设备id 查出设详细信息
                            EquipMentVo eq = alarmMapper.selectDeviceId(alarmDateVO.getDeviceId());
                            if (eq != null) {
                                //报警信息存随机的id
                                alarmIndex.setId(id);
                                eq.getName();
                                eq.getLname();
                                //报警信息存楼宇的id
                                alarmIndex.setObjId(eq.getId());
                                //报警信息存楼宇名称   如果等于0 说明是顶级 不用拼接父级名称
                                // 不等于0 就查数据库 找到父级id的名称进行拼接
                                if("0".equals(eq.getParentId())) {
                                    alarmIndex.setObjName(eq.getLname());
                                }else{
                                    //进行名称拼接
                                    String objId  = String.valueOf(((Map) deviceIdMap.get(eq.getDeviceId())).get("objId"));
                                    Map<String, Object> map = (Map) objectMap.get(objId);
                                    String objIdName = "";
                                    while(true){
                                        objIdName = objIdName == "" ? map.get("name") + objIdName : map.get("name") + "-" + objIdName;
                                        if ("0".equals(map.get("parentId"))){
                                            break;
                                        }
                                        map = (Map) objectMap.get(map.get("parentId"));
                                    }
                                    alarmIndex.setObjName(objIdName);
                                }
                                //报警信息存设备id
                                alarmIndex.setDeviceId(eq.getDeviceId());
                                //报警信息存设备类型
                                alarmIndex.setTypes(eq.getTypes());
                                //报警信息存设备的名字
                                alarmIndex.setEName(eq.getName());
                                //报警信息存报警限值
                                String index = "上限:" + up + " " + "下限:" + down;
                                alarmIndex.setAlarmStop(index);
                                //报警信息存报警值
//                                alarmIndex.setAlarmValue(Float.toString(alarmDateVO.getNow()));
                                alarmIndex.setAlarmValue(("longParticle".equals(alarmDateVO.getAttributeName()) || "littleParticle".equals(alarmDateVO.getAttributeName())) ? AlarmServiceImpl.decimalTow(alarmDateVO.getNow()) : AlarmServiceImpl.decimal(alarmDateVO.getNow()));
                                //报警信息存异常时间
                                alarmIndex.setAbnormaltime(dateFormat.format(date));
                                //属性
                                alarmIndex.setAttributes(alarmDateVO.getAttributeAlias());
                                alarmIndex.setRemark(alarmDateVO.getAttributeAlias() + "异常");

                                //设备报警信息是否处理 未处理
                                alarmIndex.setState("2");

                                alarmIndex.setType(alarmDateVO.getType());

                                alarmMapper.addAlarm(alarmIndex);
                            } else {
                                return;
                            }
                        }
                    } else {
                        Date dates = new Date();
                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss");
                        if (set.contains(alarmDateVO.getDeviceId() + "+" + alarmDateVO.getAttributeAlias())) {
                            alarmMapper.updateAlarm(alarmDateVO.getDeviceId(), dateFormat.format(dates), alarmDateVO.getAttributeAlias(), alarmDateVO.getAttributeAlias() + "恢复正常");
                        }
                    }
                } else {
                    if ((alarmDateVO.getType() == "0" || "0".equals(alarmDateVO.getType())) && (alarmMapper.selectZero(alarmDateVO.getDeviceId(), alarmDateVO.getAttributeAlias()) > 0)) {
                        Date dates = new Date();
                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd :HH:mm:ss");
                        alarmMapper.updateAlarmStop(alarmDateVO.getDeviceId(), "设备离线", "离线", dateFormat.format(dates));
                    }

                }
            }
        }
    }

    private static   String decimal (Float now){
        BigDecimal big = new BigDecimal(now);
        BigDecimal a = big.setScale(1,BigDecimal.ROUND_DOWN);
        return a.toString();
    }

    private static String decimalTow (Float now){
        BigDecimal big = new BigDecimal(now);
        BigDecimal a = big.setScale(2,BigDecimal.ROUND_DOWN);
        return a.toString();
    }


    @Deprecated
    @Override
    public Page<Alarm> queryAllPageByDTO(PageDTO pageDTO) {
        return null;
    }
}
